"""
HiAgent 知识库管理路由
提供知识库的CRUD操作接口
"""
from fastapi import APIRouter, Query, HTTPException, UploadFile, File, Form
from typing import Optional, List
from pydantic import BaseModel, Field
import os
import uuid

from src.llm.hiagent_app.services.knowledge_service import KnowledgeService
from src.middleware.response_formatter import create_success_response, create_error_response
from config.settings import settings


router = APIRouter(prefix="/api/v1/hiagent/knowledge", tags=["HiAgent Knowledge"])


# ==================== 请求模型 ====================

class CreateDatasetRequest(BaseModel):
    """创建知识库请求"""
    name: str = Field(..., description="知识库名称")
    description: str = Field("", description="知识库描述")
    workspace_id: str = Field(..., description="工作空间ID (必填)")
    icon: str = Field("upload/full/38/82/8c3fc2983b873d3092a9ccd9f6329affea3729c5ec32bb86a0026497cefe", description="图标")
    indexing_technique: Optional[int] = Field(0, description="索引技术")
    retrieval_search_method: Optional[int] = Field(0, description="检索方法")
    embed_id: str = Field("d34if2o5oc9ofekvmemg", description="嵌入模型ID")
    directory_id: str = Field("default", description="目录ID")


class UpdateDatasetRequest(BaseModel):
    """更新知识库请求"""
    name: Optional[str] = Field(None, description="知识库名称")
    description: Optional[str] = Field(None, description="知识库描述")
    icon: Optional[str] = Field(None, description="图标")


class CreateDocumentRequest(BaseModel):
    """创建文档请求"""
    dataset_id: str = Field(..., description="知识库ID")
    name: str = Field(..., description="文档名称")
    workspace_id: str = Field(..., description="工作空间ID (必填)")
    content: Optional[str] = Field(None, description="文档内容")
    file_url: Optional[str] = Field(None, description="文件URL")
    labels: Optional[List[str]] = Field(None, description="标签列表")


# ==================== 响应模型 ====================

class DatasetBrief(BaseModel):
    """知识库简要信息"""
    kb_id: str = Field(..., alias="Id", description="知识库ID")
    name: str = Field(..., alias="Name", description="知识库名称")
    description: Optional[str] = Field(None, alias="Description", description="知识库描述")
    icon: Optional[str] = Field(None, alias="Icon", description="图标")
    document_count: int = Field(0, alias="TotalDocumentCount", description="文档总数")
    created_at: Optional[str] = Field(None, alias="CreatedAt", description="创建时间")
    updated_at: Optional[str] = Field(None, alias="UpdatedAt", description="更新时间")

    class Config:
        populate_by_name = True
        allow_population_by_field_name = True


class DatasetListResponse(BaseModel):
    """知识库列表响应"""
    items: List[DatasetBrief] = Field(..., description="知识库列表")
    total: int = Field(..., description="总数")
    page: int = Field(..., description="当前页码")
    page_size: int = Field(..., description="每页数量")


# ==================== 路由接口 ====================

@router.post("/datasets", summary="创建知识库")
async def create_dataset(request: CreateDatasetRequest):
    """
    创建新的知识库

    - **name**: 知识库名称(必填)
    - **description**: 知识库描述
    - **workspace_id**: 工作空间ID(必填)
    - **icon**: 图标URL
    - **embed_id**: 嵌入模型ID
    """
    service = KnowledgeService()

    try:
        dataset_id = service.create_dataset(
            name=request.name,
            description=request.description,
            workspace_id=request.workspace_id,
            icon=request.icon,
            indexing_technique=request.indexing_technique,
            retrieval_search_method=request.retrieval_search_method,
            models={"EmbedID": request.embed_id},
            directory_id=request.directory_id
        )

        if dataset_id:
            return create_success_response(
                data={"kb_id": dataset_id},
                message="创建成功"
            )
        else:
            return create_error_response(
                message="创建失败",
                status_code=400
            )

    except Exception as e:
        return create_error_response(
            message=f"创建知识库失败: {str(e)}",
            status_code=500
        )


@router.get("/datasets", summary="获取知识库列表")
async def list_datasets(
    workspace_id: str = Query(..., description="工作空间ID (必填)"),
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(20, ge=1, le=100, description="每页数量"),
    keyword: Optional[str] = Query(None, description="关键词搜索")
):
    """
    获取知识库列表,支持分页和关键词搜索

    - **workspace_id**: 工作空间ID(必填)
    - **page**: 页码,从1开始
    - **page_size**: 每页数量,1-100
    - **keyword**: 关键词搜索
    """
    service = KnowledgeService()

    try:
        datasets, total = service.list_datasets(
            workspace_id=workspace_id,
            page_number=page,
            page_size=page_size,
            keyword=keyword
        )

        # 转换为响应格式
        items = []
        for ds in datasets:
            items.append({
                "Id": ds.kb_id,
                "Name": ds.name,
                "Description": ds.description,
                "Icon": ds.icon,
                "TotalDocumentCount": ds.document_count,
                "CreatedAt": ds.created_time,
                "UpdatedAt": ds.updated_time
            })

        return create_success_response(
            data={
                "items": items,
                "total": total,
                "page": page,
                "page_size": page_size
            },
            message="获取成功"
        )

    except Exception as e:
        return create_error_response(
            message=f"获取知识库列表失败: {str(e)}",
            status_code=500
        )


@router.get("/datasets/{dataset_id}", summary="获取知识库详情")
async def get_dataset(
    dataset_id: str,
    workspace_id: str = Query(..., description="工作空间ID (必填)")
):
    """
    获取指定知识库的详细信息

    - **dataset_id**: 知识库ID
    - **workspace_id**: 工作空间ID(必填)
    """
    service = KnowledgeService()

    try:
        dataset = service.get_dataset(dataset_id, workspace_id)

        if dataset:
            return create_success_response(
                data={
                    "dataset": {
                        "Id": dataset.kb_id,
                        "Name": dataset.name,
                        "Description": dataset.description,
                        "Icon": dataset.icon,
                        "TotalDocumentCount": dataset.document_count,
                        "Size": dataset.size,
                        "Status": dataset.status,
                        "CreatedAt": dataset.created_time,
                        "UpdatedAt": dataset.updated_time,
                        "WorkspaceID": dataset.workspace_id
                    }
                },
                message="获取成功"
            )
        else:
            raise HTTPException(status_code=404, detail="知识库不存在")

    except HTTPException:
        raise
    except Exception as e:
        return create_error_response(
            message=f"获取知识库详情失败: {str(e)}",
            status_code=500
        )


@router.put("/datasets/{dataset_id}", summary="更新知识库")
async def update_dataset(
    dataset_id: str,
    request: UpdateDatasetRequest,
    workspace_id: str = Query(..., description="工作空间ID (必填)")
):
    """
    更新知识库信息

    - **dataset_id**: 知识库ID
    - **name**: 知识库名称(可选)
    - **description**: 知识库描述(可选)
    - **icon**: 图标(可选)
    - **workspace_id**: 工作空间ID(必填)
    """
    service = KnowledgeService()

    try:
        success = service.update_dataset(
            dataset_id=dataset_id,
            workspace_id=workspace_id,
            name=request.name,
            description=request.description,
            icon=request.icon
        )

        if success:
            return create_success_response(
                message="更新成功"
            )
        else:
            return create_error_response(
                message="更新失败",
                status_code=400
            )

    except Exception as e:
        return create_error_response(
            message=f"更新知识库失败: {str(e)}",
            status_code=500
        )


@router.delete("/datasets/{dataset_id}", summary="删除知识库")
async def delete_dataset(
    dataset_id: str,
    workspace_id: str = Query(..., description="工作空间ID (必填)")
):
    """
    删除指定的知识库

    - **dataset_id**: 知识库ID
    - **workspace_id**: 工作空间ID(必填)
    """
    service = KnowledgeService()

    try:
        success = service.delete_dataset(dataset_id, workspace_id)

        if success:
            return create_success_response(
                message="删除成功"
            )
        else:
            return create_error_response(
                message="删除失败",
                status_code=400
            )

    except Exception as e:
        return create_error_response(
            message=f"删除知识库失败: {str(e)}",
            status_code=500
        )


# ==================== 文档管理接口 ====================

@router.post("/documents", summary="创建文档")
async def create_document(request: CreateDocumentRequest):
    """
    向知识库添加文档

    - **dataset_id**: 知识库ID(必填)
    - **name**: 文档名称(必填)
    - **workspace_id**: 工作空间ID(必填)
    - **content**: 文档内容(content和file_url至少提供一个)
    - **file_url**: 文件URL或ObsUrl(content和file_url至少提供一个)
    - **labels**: 标签列表(可选)

    注意：如果提供content，会先上传到HiAgent服务器获取ObsUrl
    """
    from src.llm.hiagent_app.utils.file_uploader import HiAgentFileUploader
    from urllib.parse import urlparse, parse_qs

    service = KnowledgeService()
    obs_url = request.file_url

    try:
        # 如果提供了content而不是file_url，需要先上传文件
        if request.content and not obs_url:
            # 上传内容到HiAgent（使用正确的host）
            uploader = HiAgentFileUploader(host="agent.swjtu.edu.cn")
            content_bytes = request.content.encode('utf-8')
            download_url = uploader.upload(content_bytes, request.name)

            if not download_url:
                return create_error_response(
                    message="上传文档内容到HiAgent失败",
                    status_code=500
                )

            # 从下载 URL 中提取 ObsUrl
            parsed = urlparse(download_url)
            params = parse_qs(parsed.query)
            if 'Path' in params and len(params['Path']) > 0:
                obs_url = params['Path'][0]
            else:
                return create_error_response(
                    message="无法从上传响应中提取ObsUrl",
                    status_code=500
                )

        # 使用obs_url创建文档
        document_id = service.create_document(
            dataset_id=request.dataset_id,
            name=request.name,
            workspace_id=request.workspace_id,
            file_url=obs_url,
            labels=request.labels
        )

        if document_id:
            return create_success_response(
                data={"document_id": document_id},
                message="文档创建成功"
            )
        else:
            return create_error_response(
                message="文档创建失败",
                status_code=400
            )

    except Exception as e:
        return create_error_response(
            message=f"创建文档失败: {str(e)}",
            status_code=500
        )


@router.post("/documents/upload", summary="上传文档文件")
async def upload_document(
    dataset_id: str = Form(..., description="知识库ID"),
    file: UploadFile = File(..., description="文档文件"),
    workspace_id: str = Form(..., description="工作空间ID (必填)"),
    labels: Optional[str] = Form(None, description="标签，逗号分隔"),
    use_hiagent: bool = Form(True, description="是否上传到HiAgent服务器")
):
    """
    上传文件到知识库

    - **dataset_id**: 知识库ID(必填)
    - **file**: 上传的文件(必填)
    - **workspace_id**: 工作空间ID(必填)
    - **labels**: 标签，逗号分隔(可选)
    - **use_hiagent**: 是否上传到HiAgent服务器(默认:True)
    """
    from src.llm.hiagent_app.utils.file_uploader import HiAgentFileUploader
    from urllib.parse import urlparse, parse_qs

    service = KnowledgeService()
    file_path = None
    obs_url = None

    try:
        # 读取文件内容
        content = await file.read()
        print(f"[Router] use_hiagent={use_hiagent}, file={file.filename}, size={len(content)}")

        # 根据 use_hiagent 参数决定上传位置
        if use_hiagent:
            print(f"[Router] Uploading to HiAgent server...")
            # 上传到 HiAgent 服务器（使用正确的host）
            uploader = HiAgentFileUploader(host="agent.swjtu.edu.cn")
            download_url = uploader.upload(content, file.filename)
            print(f"[Router] HiAgent upload result: {download_url}")

            if not download_url:
                print(f"[Router] HiAgent upload failed, returning error")
                return create_error_response(
                    message="上传到HiAgent服务器失败",
                    status_code=500
                )

            # 从下载 URL 中提取 ObsUrl
            parsed = urlparse(download_url)
            params = parse_qs(parsed.query)
            if 'Path' in params and len(params['Path']) > 0:
                obs_url = params['Path'][0]
                print(f"[Router] Extracted ObsUrl: {obs_url}")
            else:
                print(f"[Router] Failed to extract ObsUrl from download URL")
                return create_error_response(
                    message="无法从上传响应中提取ObsUrl",
                    status_code=500
                )

            upload_location = "HiAgent服务器"
            file_url_display = download_url
            print(f"[Router] Successfully uploaded to HiAgent, ObsUrl: {obs_url}")
        else:
            print(f"[Router] Saving to local server...")
            # 保存到本地服务器
            file_extension = os.path.splitext(file.filename)[1]
            unique_filename = f"{uuid.uuid4()}{file_extension}"
            file_path = os.path.join(settings.upload_path, unique_filename)

            # 确保上传目录存在
            os.makedirs(settings.upload_path, exist_ok=True)

            # 保存文件
            with open(file_path, "wb") as f:
                f.write(content)

            obs_url = file_path
            file_url_display = file_path
            upload_location = "本地服务器"
            print(f"[Router] Successfully saved to local: {file_path}")

        # 解析标签
        label_list = None
        if labels:
            label_list = [label.strip() for label in labels.split(",") if label.strip()]

        # 创建文档记录（使用 ObsUrl）
        document_id = service.create_document(
            dataset_id=dataset_id,
            name=file.filename,
            workspace_id=workspace_id,
            file_url=obs_url,
            labels=label_list
        )

        if document_id:
            return create_success_response(
                data={
                    "document_id": document_id,
                    "filename": file.filename,
                    "file_url": file_url_display,
                    "obs_url": obs_url,
                    "upload_location": upload_location,
                    "size": len(content)
                },
                message="文件上传成功"
            )
        else:
            # 如果创建文档失败，删除已上传的本地文件
            if file_path and os.path.exists(file_path):
                os.remove(file_path)
            return create_error_response(
                message="文档创建失败",
                status_code=400
            )

    except Exception as e:
        # 清理可能已保存的本地文件
        if file_path and os.path.exists(file_path):
            os.remove(file_path)
        return create_error_response(
            message=f"上传文件失败: {str(e)}",
            status_code=500
        )


@router.get("/datasets/{dataset_id}/documents", summary="获取文档列表")
async def list_documents(
    dataset_id: str,
    workspace_id: str = Query(..., description="工作空间ID (必填)"),
    page: int = Query(1, ge=1, description="页码"),
    page_size: int = Query(20, ge=1, le=100, description="每页数量"),
    keyword: Optional[str] = Query(None, description="关键词搜索")
):
    """
    获取知识库的文档列表

    - **dataset_id**: 知识库ID
    - **workspace_id**: 工作空间ID(必填)
    - **page**: 页码，从1开始
    - **page_size**: 每页数量，1-100
    - **keyword**: 关键词搜索
    """
    service = KnowledgeService()

    try:
        documents, total = service.list_documents(
            dataset_id=dataset_id,
            workspace_id=workspace_id,
            page_number=page,
            page_size=page_size,
            keyword=keyword
        )

        return create_success_response(
            data={
                "items": documents,
                "total": total,
                "page": page,
                "page_size": page_size
            },
            message="获取成功"
        )

    except Exception as e:
        return create_error_response(
            message=f"获取文档列表失败: {str(e)}",
            status_code=500
        )


@router.delete("/documents/{document_id}", summary="删除文档")
async def delete_document(
    document_id: str,
    workspace_id: str = Query(..., description="工作空间ID (必填)"),
    dataset_id: Optional[str] = Query(None, description="知识库ID")
):
    """
    删除指定的文档

    - **document_id**: 文档ID（必填）
    - **workspace_id**: 工作空间ID（必填）
    - **dataset_id**: 知识库ID（可选，某些情况下API可能需要）

    注意：HiAgent API文档中DeleteDocument的请求参数定义不完整，
    根据其他API的模式，可能需要提供dataset_id以确保正确删除。
    """
    service = KnowledgeService()

    try:
        success = service.delete_document(
            document_id=document_id,
            workspace_id=workspace_id,
            dataset_id=dataset_id
        )

        if success:
            return create_success_response(
                message="文档删除成功"
            )
        else:
            return create_error_response(
                message="文档删除失败",
                status_code=400
            )

    except Exception as e:
        import traceback
        traceback.print_exc()
        return create_error_response(
            message=f"删除文档失败: {str(e)}",
            status_code=500
        )


@router.post("/datasets/{dataset_id}/query", summary="知识库检索")
async def query_knowledge(
    dataset_id: str,
    query: str = Query(..., description="检索查询"),
    workspace_id: str = Query(..., description="工作空间ID (必填)"),
    top_k: int = Query(5, ge=1, le=20, description="返回结果数量"),
    score_threshold: Optional[float] = Query(None, ge=0.0, le=1.0, description="相似度阈值")
):
    """
    在知识库中检索相关内容（使用HiAgent原生Query API）

    - **dataset_id**: 知识库ID
    - **query**: 检索查询内容（关键词）
    - **workspace_id**: 工作空间ID(必填)
    - **top_k**: 返回结果数量，1-20（默认：5）
    - **score_threshold**: 相似度阈值，0.0-1.0（可选，用于过滤低分结果）

    **返回数据说明：**
    - 每个结果包含：
      - Content: 检索到的文本内容
      - Score: 相似度分数（0-1之间，越高越相关）
      - DatasetID/DatasetName: 知识库信息
      - DocumentID/DocumentName: 文档信息
      - SegmentID: 文档片段ID
      - Serial: 片段序号
      - 其他元数据（文件类型、索引等）

    **示例：**
    ```
    POST /api/v1/hiagent/knowledge/datasets/{dataset_id}/query?query=测试&top_k=5
    ```
    """
    service = KnowledgeService()

    try:
        results = service.query_knowledge(
            dataset_id=dataset_id,
            query=query,
            workspace_id=workspace_id,
            top_k=top_k,
            score_threshold=score_threshold
        )

        # 格式化结果，添加有用的摘要信息
        formatted_results = []
        for result in results:
            formatted_result = {
                "score": result.get("Score", 0),
                "content": result.get("Content", ""),
                "dataset_id": result.get("DatasetID", ""),
                "dataset_name": result.get("DatasetName", ""),
                "document_id": result.get("DocumentID", ""),
                "document_name": result.get("DocumentName", ""),
                "segment_id": result.get("SegmentID", ""),
                "serial": result.get("Serial"),
                "file_type": result.get("DocumentFileType"),
                "doc_type": result.get("DocumentType"),
                # 保留原始数据以便需要时访问
                "_raw": result
            }
            formatted_results.append(formatted_result)

        return create_success_response(
            data={
                "query": query,
                "dataset_id": dataset_id,
                "results": formatted_results,
                "total": len(formatted_results),
                "top_k": top_k,
                "score_threshold": score_threshold
            },
            message=f"检索成功，找到 {len(formatted_results)} 条结果"
        )

    except Exception as e:
        import traceback
        traceback.print_exc()
        return create_error_response(
            message=f"知识库检索失败: {str(e)}",
            status_code=500
        )
